package com.media.selector.camera

import android.app.Activity
import android.content.ContentValues
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.util.DisplayMetrics
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.MimeTypeMap
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import androidx.core.net.toFile
import androidx.core.os.EnvironmentCompat
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.media.selector.BR
import com.media.selector.MediaSelector
import com.media.selector.R
import com.media.selector.databinding.FragmentCameraBinding
import com.media.selector.media.helper.MediaPath
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

/**
 * date        ：2020/4/20
 * author      ：蒙景博
 * description ：
 */
class CameraFragment : Fragment() {

    companion object {
        private const val PHOTO_PREFIX = "IMG_"
        private const val FILENAME = "yyyyMMdd_HHmmss"
        private const val PHOTO_EXTENSION = ".jpg"
        private const val RATIO_4_3_VALUE = 4.0 / 3.0
        private const val RATIO_16_9_VALUE = 16.0 / 9.0
    }

    private lateinit var mBinding: FragmentCameraBinding
    private lateinit var mCameraExecutor: ExecutorService

    // 闪光灯，默认自动
    private var mFlashMode: Int = ImageCapture.FLASH_MODE_AUTO
    // 镜头，默认使用后置镜头
    private var mLensFacing: Int = CameraSelector.LENS_FACING_BACK

    private var mImageCapture: ImageCapture? = null

    private val mMetrics by lazy { DisplayMetrics().also { mBinding.cameraPreview.display.getRealMetrics(it) } }
    private val mScreenAspectRatio by lazy { aspectRatio(mMetrics.widthPixels, mMetrics.heightPixels) }
    private val mRotation by lazy { mBinding.cameraPreview.display.rotation }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_camera, container, false)
        mBinding.lifecycleOwner = this
        mBinding.setVariable(BR.data, this)
        return mBinding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        mCameraExecutor = Executors.newSingleThreadExecutor()
        // 给CameraX绑定生命周期
        mBinding.cameraPreview.post { bindCameraUseCases() }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        mCameraExecutor.shutdown()
    }

    fun onClick(v: View) {
        when(v.id){
            R.id.camera_close_container -> requireActivity().onBackPressed()
            R.id.camera_flash_container -> doSwitchFlashMode()
            R.id.camera_switch_container -> doSwitchLensFacing()
            R.id.camera_capture_button -> doTakePicture()
        }
    }

    /**
     * 切换摄像头
     */
    private fun doSwitchLensFacing() {
        mBinding.cameraSwitchContainer.postDelayed({
            mLensFacing = if (CameraSelector.LENS_FACING_FRONT == mLensFacing) {
                CameraSelector.LENS_FACING_BACK
            } else {
                CameraSelector.LENS_FACING_FRONT
            }
            bindCameraUseCases()
        }, 50)
        // 切换镜头时会有短暂的白屏，这里在切换时预先设置一个背景色，使用Handler发送延迟消息在更新
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mBinding.cameraPreview.foreground = ColorDrawable(Color.BLACK)
            mBinding.cameraPreview.postDelayed({
                mBinding.cameraPreview.foreground = null
            }, 800)
        } else {
            mBinding.cameraPreview.background = ColorDrawable(Color.BLACK)
            mBinding.cameraPreview.postDelayed({
                mBinding.cameraPreview.background = null
            }, 800)
        }
    }

    /**
     * 切换闪光灯
     */
    private fun doSwitchFlashMode() {
        mFlashMode = when (mFlashMode) {
            ImageCapture.FLASH_MODE_AUTO -> {
                mBinding.cameraFlash.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.svg_camera_flash_off))
                ImageCapture.FLASH_MODE_OFF
            }
            ImageCapture.FLASH_MODE_OFF -> {
                mBinding.cameraFlash.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.svg_camera_flash_on))
                ImageCapture.FLASH_MODE_ON
            }
            else -> {
                mBinding.cameraFlash.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.svg_camera_flash_auto))
                ImageCapture.FLASH_MODE_AUTO
            }
        }
        mImageCapture?.flashMode = mFlashMode
    }

    private fun bindCameraUseCases() {
        val mCameraSelector = CameraSelector.Builder().requireLensFacing(mLensFacing).build()
        val mCameraProvider = ProcessCameraProvider.getInstance(requireContext())
        mCameraProvider.addListener(Runnable {
            val mProvider = mCameraProvider.get()
            // 预览
            val mPreview = Preview.Builder()
                .setTargetAspectRatio(mScreenAspectRatio)
                .setTargetRotation(mRotation)
                .build()
            // 拍照
            mImageCapture = ImageCapture.Builder()
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                .setFlashMode(mFlashMode)
                .setTargetAspectRatio(mScreenAspectRatio)
                .setTargetRotation(mRotation)
                .build()
            mProvider.unbindAll()
            try {
                val mCamera = mProvider.bindToLifecycle(this, mCameraSelector, mPreview, mImageCapture)
                mPreview.setSurfaceProvider(mBinding.cameraPreview.createSurfaceProvider())
            }catch (e: Exception) {
                Log.e(this.javaClass.simpleName, e.message ?: "")
            }
        }, ContextCompat.getMainExecutor(requireContext()))
    }

    /**
     * 计算宽高比 4:3或16:9
     */
    private fun aspectRatio(width: Int, height: Int): Int {
        val previewRatio = max(width, height).toDouble() / min(width, height)
        if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) {
            return AspectRatio.RATIO_4_3
        }
        return AspectRatio.RATIO_16_9
    }

    /**
     * 拍照
     */
    private fun doTakePicture() {
        // 创建拍照后输出地址
        val mImageName = "$PHOTO_PREFIX${SimpleDateFormat(FILENAME, Locale.getDefault()).format(System.currentTimeMillis())}$PHOTO_EXTENSION"
        val mContentValues = ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME, mImageName)
            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg")
        }
        val mOutputFileOptions = ImageCapture.OutputFileOptions.Builder(requireContext().contentResolver, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mContentValues)
            .setMetadata(ImageCapture.Metadata().apply {
                isReversedHorizontal = mLensFacing == CameraSelector.LENS_FACING_FRONT
            })
            .build()
        mImageCapture?.let { capture->
            capture.takePicture(mOutputFileOptions, mCameraExecutor, object : ImageCapture.OnImageSavedCallback {

                override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
                    // 拍照完成跳转至预览页面
                    findNavController().navigate(R.id.action_jump_CameraPreviewFragment, Bundle().apply {
                        putString(CameraPreviewFragment.PHOTO_URI, "${outputFileResults.savedUri}")
                    })
                }

                override fun onError(exception: ImageCaptureException) {
                    with(requireActivity()) {
                        setResult(Activity.RESULT_OK, Intent().putExtra(MediaSelector.EXTRA_TAKE_PHOTO_STATE, false))
                        finish()
                    }
                }
            })
        }
    }
}